Modelos atuais conseguem representar quaisquer padrões nos dados, infelizmente eles podem over fitar (representar padrões que não são reproduziveis no decorrer do tempo), para avaliar modelos precisamos de uma metodologia sitemática. Nesse capítulo serão descritas técnicas para garantir um mesmo resultado para modelos no decorrer do tempo e evitar overfit. Nesse capítulo assume-se que os dados são representativos da população e que há uma qualidade mínima na proveniência de dados das amostras.
Com essas condições, nosso objetivo é tunar o modelo sem overfita-lo. Para tal dividimos o conjunto de dados em treino/teste, abordagens mais modernas dividem em vários conjuntos de treino/teste para atingir um resultado melhor do modelo.
Técnicas que aprendem muito bem a estrutura dos dados tão bem que ao ser aplicado nos dados onde o modelo foi construído prediz corretamente \(100%\) da amostra. Além de aprender os padrões gerais de comportamento dos dados o modelo aprendeu o ruído de cada dado, isso significa que o modelo overfitou
Conjunto de treino com dois preditores
A figura acima, será usada para ilustrar o conceito de over-fitting, contém \(208\) exemplos e é um problema de classificação binária, com duas variáveis preditoras. Há um leve desbalanceamento nas classes \(111\) classe 1 e \(97\) classe 2 além disso existe uma sobreposição de classes, um problema tipicamente encontrado. Um modelo que use esses dados tem tipicamente um objetivo: predizer novos dados, o modelo pode ser representado como um fronteira(s) de decisão(ões).
Fronteiras de decisão
A figura acima mostra dois possíveis modelos para solucionar esse problema, o primeiro separa cada conjunto de dados da classe 1 e alega que o restante seria da classe 2. Podemos perceber que esse padrão não é muito generalizável. O modelo da direita, apresenta uma fronteira de decisão menos rígida que não classifica corretamente todos os pontos, mas tem maior probabilidade de generalizar.
Nesse exmplo simplista, com apenas duas variáveis, é simples observar o over-fitting do modelo da esquerda. No mundo real modelos tem muitas outras variáveis tornando essa abordagem visual impraticável. Necessitamos de uma ferramenta para averiguar o grau de over-fitting.
Muitos modelos tem parâmetros impossíveis de serem estimados usando os dados, como o KNN, devemos informar o número de vizinhos. Ao escolher muitos vizinhos podemos não conseguir aprender o suficiente dos dados, ao escolher poucos podemos facilmente over-fittar. Esse tipo de parâmetro é conhecido por: parâmetro de tunning muitos modelos apresentam pelo menos um desses parâmetros.
A escolha desses parâmetros aumentam ou reduzem o grau de especialização do modelo, podendo, causar over-fitting. POr exemplo o parâmetro custo do SVM C que informa o peso do erro de classificação do modelo, ao setar um valor grande para esse parâmetro, temos um modelo altamente over-fittado enquanto que um valor baixo indica um modelo com resultados baixos. No painel da direita da figura fronteiras de decisão foi escolhido um valor alto, no painel da esquerda foi escolhido um valor usando validação cruzada.
Uma abordagem para escolha de parâmetros é selecionar um subconjunto deles, treinar diversos modelos e observar o melhor entre eles. Esse processo pode ser visualizado na figura abaixo:
Após selecionar um conjuntto de parâmetros aceitáveis para treinarmos o modelo devemos encontrar uma métrica (confiável) para avaliarmos sua performance. Nesse ponto aplicamos uma estratégia de força bruta nos dados e nos parâmetros para encontrarmos o melhor modelo e parâmetro. Outras abordagens para encontrar os parâmetros ótimo são usar algoritmos genéticos ou métodos de de busca baseados em simplex.
O maior problema é encontrar uma estimativa confiável para esses modelos e definir qual o melhor dentre eles, como vimos anteiormente taxa de erro pode nos levar a uma falsa sensação de segurança. Uma abordagem usada é testar o modelo para uma amostra não usada para treinar o mesmo, seu tamanho deve ser considerável.
Uma outra abordagem é usar um conjunto apenas de teste reamostrando o conjunto de treinamento, para realizar isso existem algumas técnicas estatísticas que serão abordadas adiante.
O coração do processo para encontrar os parâmetros ótimo é a divisão do conjunto de dados, a construção do modelo segue os seguintes passos:
Dado que há um conjunto fixo de pontos de amostra, o modelador deve decidir como distribui-los nessas etapas. A principal escolha são os pontos que serão usados para avaliar o modelo, idealmente não devem ser os mesmos usados para treinar/ajustar finamente o modelo, dessa forma, eles representam valores não viesados. Quando há um conjunto de dados grande e expressivo podemos separar os conjuntos em validação e teste sem problemas, usando um para treinar e outro para validar.
Quando não há um conjunto de dados grande o suficiente não fazemos um conjunto de validação pois cada instância deve ser usada para treinar o modelo. Além disso o conjunto de teste que seria usado pode não ter poder preditivo suficiente para tomar deciões precisas. Muitos pesquisadores reportaram que usar apenas um conjunto de dados é uma decisão pobre em termos de performance. Usar a validação cruzada é uma alternativa melhor e viável.
Se um conjunto de teste é estritamente necessário podemos tomar algumas ações:
Na maioria dos casos não há desejo em transformar os conjuntos de treino e teste em homogeneos, Amostragens aleatórias podem ser usadas para criar datasets equivalentes.
A forma mais simples para criar conjuntos de treino/teste é tomar amostras aleatórias, não considera informação sobre desbalanceamento entre classes, quando ocorre desbalancemento a distribuição entre classes do output do modelo pode variar muito entre o treino/teste.
Uma alternativa é usar uma amostragem estratificada ao separar os dados, que é uma amostra aleatória aplicada em subgrupos (acredito que aqui seja o upsampling e downsampling)
Os dados também podem ser divididos entre os valores das variáveis preditoras, uma proposta aceita na literatura é maximizar a dissimilaridade amostral. Há muitas formas para calcular a dissimilaridade amostral a mais comum é usar a distância entre dois pontos de um mesmo preditor, se a distância é pequena os pontos estão próximos, caso contrário estão longe (indicador de dissimilaridade). Para usar esse conceito como ferramenta suponha que o conjunto de teste foi inicializado com apenas uma instância. A dissimilaridade entre esse ponto e os pontos não alocados pode ser calculada. O ponto não alocado com maior dissimilaridade deve ser adicionado ao conjunto de teste. Para adicionar mais pontos será necessário um método para calcular a dissimilaridade entre um ponto e um conjunto, uma abordagem é usar o valor médio de dissimilaridade.
Calcula-se a dissimilaridade média dos pontos adicionados ao conjunto de dados, depois escolhemos o ponto (no conjunto não alocado) com maior dissmilaridade em relação a média de dissimilaridade do conjunto adicionado e adicionamos ele ao conjunto alocado esse processo continua até atingirmos o tamanho do conjunto de teste desejado.
A Figura abaixo mostra esse processo aplicado em um problema de classificação de dados, nesse tipo de problema a técnica de maximização é aplicada dentro de cada classe separadamente, nesse exemplo não foi usada a média entre grupos mas sim o mínimo.
Maximização de dissimilaridade para classificação
De uma maneira geral técnicas de reamostragem usadas para avaliar a performance do modelo trabalham de forma parecida. Uma parte dos dados é usada para fitar o modelo e a outra é usada para testar a eficácia dos dados, esse processo é repetido diversas vezes os resultados são sumarizados e agregados. A diferença das tecnicas de reamostragem residem na forma como as subamostras são selecionados.
As instâncias são divididas em k partições com tamanhos aproximados, um modelo é fitado usando 9 partições e testado com a última. Esse processo é repetido 10 vezes trocando a partição de teste por uma que nunca foi usada para teste, na figura abaixo notamos um 3-fold cross-validation: Uma variação dessa estratégia é fazer uma amostragem estratíficada por classes em cada um dos folds. Outra variação, leave one out cross-validation (LOOCV), é um caso especial onde k é igual ao número de instâncias, removemos uma e treinamos com as outras. O modelo final é calculado pela sumarização das k instâncias deixadas de fora uma a uma.
Não há definição formal sobre qual o melhor valor de k tipicamente são usados os valores \({5, 10}\) quanto maior o valor de k menor o bias da técnica. Com o aumento de k a diferença entre conjuntos de treino e teste reduz.
Um ponto importante sobre técnicas de reamostragem é incerteza (variação/ruído), um método sem viés pode predizer o valor correto mas paga um preço alto para isso, incerteza. O que significa que repetir o processo de re amostragem pode produzir resultados distintos. Validação cruzada possuí alta variação comparada a outras técnicas, porém para grandes conjuntos de treino essa variância pode ser desprezada.
Valores grandes de k são computacionalmente onerosos, LOOCV é o mais computacionalmente intenso dentre todas as técnicas pois necessita de um modelo distinto para cada ponto e cada subconjunto tem o tamanho da amostra menos um. Tem pesquisas que mostram que o leave one out é tão efetivo quanto uma validação cruzada para \(k=10\). Valores pequenos de k tem um bias alto mas são menos computacionalmente onerosos, esse bias é quase o mesmo obtido por um bootstrap porém com uma variância muito maior.
Para modelos lineares de regressão para aproximar o erro do leave-one-out. O generalized Cross-validation (GCV) estatística não exige refitar o modelo para cada subamostra \[ GCV = \frac{1}{n} \sum_{i=1}^{n} \frac{y_i - \hat{y_i}}{1 - \frac{df}{n}} \] onde \(y_i\) é o i-ésimo rótulo, \(\hat{y_i}\) é a i-ésima predição do modelo e \(df\) são os graus de liberdade do modelo (parâmetros estimados pelo mesmo) que é uma medida de complexidade para modelos lineares. Dois modelos com a mesma soma de erro quadrado terão diferentes GCV se a complexidade dos modelos forem distintas. Vale ressaltar que é uma fórmula fechada.
É conhecido por leave-group-out cross-validation, monte carlo cross-validation, cria muitas divisões dos dados de treino e teste, a proporção de dados para cada subamostra e o número de repetições são controlados pelo analista. Como falamos anteriormente, o bias reduz conforme a quantidade de dados na amostra se aproxima do conjunto de modelagem valores tipicamente usados são: 75% - 80% . A figura abaixo exemplifica esse esquema:
Pode-se observar que a diferença fundamental entre essa estratégia e a validação cruzada é que pode haver repetição de instâncias podem ser representadas em vários grupos deixados para predizer. Além disso o número de repetições aqui tende a ser muito maior que uma validação cruzada.
O número e repetições é importante pois ao aumentarmos ele decrementamos a incerteza do modelo. Para resultados com alta instabilidade 20 repetições seriam suficientes, para obter um score mais estável podemos colocar 50-200 repetições. Esse valor é uma proporção dos exemplos sendo alocados no conjunto de predição, quanto maior a porcentagem mais repetições serão necessárias para reduzir a incerteza do modelo
É uma amostragem com reposição, ou seja, após um ponto ser selecionado para o fold/set ele ainda fica disponível para ser reselecionado novamente. Uma amostra de bootstrap tem o mesmo tamanho do dataset original, como resultado direto alguns pontos serão selecionados mais de uma vez e outros não serão selecionados. Os pontos não selecionados são conhecidos por out-of-bag, uma iteração de bootstrap usa os exemplos selecionados para treinar o modelo e os out-of-bag para testar. Na figura abaixo podemos ver um exemplo disso:
Bootstrap
De uma forma geral as taxas de erro de bootstrap tem menos incerteza que um k-fold, entretanto \(63.25\%\) dos pontos são representados pelo menos uma vez, portanto essa técnica tem um bias similar ao k-fold para \(k=2\). Se o conjunto de treino for pequeno esse bias é grande caso contrário pode ser desprezado.
Alguns métodos foram propostos para reduzir esse bias, um deles é conhecido por 632 method que é uma combinação de um booststrap simples com uma repredição do conjunto de treino. Por exemplo um modelo de classificação usando esse método seria: \[ (0.632 \times \textrm{bootstrap estimate}) + (0.368 \times \textrm{apparent error rate}) \] Esse novo bootstrap reduz o bias mas pode ser instável para amostras pequenas. Essa estimação pode resultar em resultados indevidamente otimistas quando o modelo overfita gravemente. Uma técnica nova foi realizada para ajustar a estimativa de erro do bootstrap denominada 632+method
Pode-se aplicar modelos estatísticos para escoragem de crédito. Dados existentes podem ser usados para criar um modelo que prediga se um aplicante à crédito tem bom crédito ou não. Essa informação pode ser usada para definir o risco do banco que está emprestando dinheiro.
German credit data é um dataset muito usado para atividades de ML, contém \(1000\) instâncias, rótulos de bom e mal pagador. O dataset é desbalancedo pois \(70\%\) são bons pagadores. Se chutassemos todos os exemplos como sendo: bom pagador teríamos uma acurácia de \(70\%\), portanto o baseline usado de acurácia deve ser no mínimo \(70\%\). (Eu discordo dos autores, essa abordagem é viável mas seria mais simples usar um F1 por exemplo)
Alguns preditores são numéricos mas a maioria é categorica, as categoricas foram binarizadas, \(800\) instâncias serão usadas para treino e \(200\) para teste. O objetivo desse capítulo é ilustrar como tunar um modelo usando reamostragem.
Como escolher o melhor modelo? Uma idéia é pegar o que tiver o melhor score e usar. Um modelo não linear SVM foi fitado para valores de custo entre \(2^{-2}\) até \(2^{7}\). Cada modelo foi testado com cinco repetições de 10-fold cross-validation as figuras abaixo mostram os valores de acurácia para
acurácia x valor do custo
acurácia x valor do custo
Para cada modelo foram gerados 50 estimativas da acuráciaos pontos vermelhos do gráficos são as médias dessas estimativas as barras são 2 \(\pm\) desvios padrão da média do erro. O profile de treinamento mostra um incremento na acurácia até o valor de custo 8 depois disso temos um decréscimo contínuo indicando um overfitting. Perceba que pela acurácia aparente o modelo melhora a medidad que o custo aumenta até 8, depois ocorre um overfitting.
Escolher o ponto de ótimo para o modelo pode não ser um boa idéia dado que são preferíveis modelos mais simples do que os complexos. Uma abordagem diferente é one-standard error que encontra o valor de ótimo e ao mesmo tempo seu erro padrão, em seguida procura o modelo mais simples com distância de um erro padrão do melhor valor numérico. Na figura abaixo podemos ver que o valor de acurácia para custo 8 é \(0.7\%\) essa técnica encontrará o melhor modelo com acurácia não menos que \(74.3%\) (\(75\% - 0.7\%\)) escolhendo o valor de custo \(2\).
Outra abordagem é escolher um modelo mais simples dentro de uma certa tolerância do valor numérico ótimo. O percentual de descréscimo da performance pode ser calculado por \((X-O)/O\) onde \(X\) é a performance e \(O\) é o valor numérico ótimo. Por exemplo, na figura com o custo do SVM a melhor acurácia de acordo com o profile foi \(75\%\) se uma perda de 4 na acurácia for aceitável, como trade off para um modelo mais simples, valores de acurácia maiores que \(71.2\%\) poderiam ser aceitos, um valor de custo \(1\) poderia ser aceito nesse modelo.
Na figura abaixo foram testados diversos métodos de reamostragem entre eles: 10-fold cross-validation, LOOCV, repeated cross-validation, bootstrap (com e sem ajuste \(632\)) e repeated training/test split (\(20\%\) de held-out). Os últimos dois usando reamostragem de 50 para estimar a performance.
Bootstrap
Todas as validações cruzadas apresentam um padrão de ponto ótimo entre \(4\) e \(16\) seguidos de uma queda de desempenho, muito provável overfitting. Com excessão do bootstrap \(632\) todas as técnicas tem um pico, que é atingido rapidamente, seguido pela queda do overfitting. As técnicas de cross-validation tem acurácia entre \(74.5\%\) \(76.6\%\). O bootstrap simples tem o pior desempenho \(74.2\%\) e o bootstrap \(632\) super compensa o bias e estima com \(82.3\%\) de acurácia.
A largura do erro padrão do 10-fold cross-validation é a maior de todas pois o erro padrão é uma função do número de reamostragens usadas (10 versus as 50 usadas pelo bootstrap). A velocidade de computação o método mais rápido é: 10-fold cross validation, em seguida temos, quase empatados, repeated cross validation, bootstrap e repeated training/test e LOOCV é o mais demorado.
Pontos negativos em usar um conjunto de teste único e independente:
1 - É uma validação única e não avalia incertezas nos resultados 2 - Proporcionalmente conjuntos de dados grandes aumentam o bias da estimativa de performance 3 - Com conjuntos de dados pequenos: 3a - O modelo necessitará de todos os pontos para estimar corretamente 3b - A incerteza do conjunto de teste pode ser conisderavelmente maior dado que conjuntos de teste distintos produzem resultados diferentes 4 - metodos de reamostragem produzem resultados aceitáveis de como o modelo vai performar no futuro
Não existe um método melhor que outro, há diversas situações onde devem ser avaliados os trade-offs. Para conjuntos de dados pequenos é melhor um 10-fold cross-validation pois o bias e variância serão ok e o custo computacional, dado o tamanho da amostra, não será elevado. Se o objetivo é escolher entre modelos em oposição a escolher o melhor indicador de performance, seria recomendável escolher uma técnica de bootstrap pois sua variância é baixa. Para conjuntos de dados grandes a diferença entre métodos se torna irrelevante e escolhemos entre poder computacional tipo um 10-fold cross-validation (discordo do autor, devemos usar um método para obter o melhor modelo mesmo que demore a execução).
Depois de escolher os parâmetros ótimos para cada modelo, devemos escolher qual o melhor modelo entre todos. Essa tarefa é bem complexa, para tal, devemos seguir o seguinte procedimento:
1 - Começar com modelos complexos como SVM, Boosted tree que produzem resultados ótimos 2 - Usar modelos mais simples e quase interpretáveis MARS, partial least squares, generalized aditive models, naive bayes 3 - Considere usar o modelo mais simples possível dentro da performance esperada (é um trade-off).
Dessa forma, podemos achar o teto de performance e depois ponderar até onde podemos perder de precisão para ganhar em interpretabilidade. No geral a maioria dos modelos tem resultados próximos então podemos escolher de acordo com os benefícios das diferentes metodologias. Complexidade, interpretabilidade, facilidade em predizer. Um SVM e random forest tem acurácia excelente porém suas complexidades computacionais podem impedir de colocarmos eles em produção, se um MARS tiver desempenho levemente inferior podemos usar ele pois tem um tempo de execução muito inferior.
Considerando o exemplode scoragem de crédito onde usamos um SVM com repeated 10-fold cross-validation a acurácia estimada do modelo era de \(75\%\) com a maioria dos resultados de reamostragem entre \(66\%\) e \(82\%\). Usando uma logistica com o mesmo schema de cross-validation obtivemos \(74.9\%\) com a maioria dos resultados de reamostragem entre \(66\%\) e \(82\%\). As mesmas \(50\) reamostragens foram usadas para avaliar cada modelo, a figura abaixo mostra a distribuição de ambos
Bootstrap
Dado que a acurácia foi metrificada usando o mesmo conjunto de dados reamostrado da mesma forma, estatísticas para comparasão em pares podem ser usadas para determinar se as diferenças entre modelos é estatisticamente significante. Um t-test pareado pode ser usado para comparar se a acurácia (média) dos modelos, ou a diferença média na acurácia dos data sets reamostrados é zero. Para ambos os modelos a diferença média na acurácia dos modelos foi de \(0.1\%\) com a logistica tendo resultados melhores. O intervalo de confiança de \(95\%\) foi de (\(-1.2\%\), \(1\%\)) indicando que a acurácia de nenhum dos modelos é significantemente melhor.
Quando são usadas várias metodologias para comparar modelos podemos chegar em situações conflitantes, dependendo do problema a ser tratado devemos considerar o peso de uma estatística maior que de outro. Especificidade e sensitividade podem ser usados para comparar modelos. Se o conjunto de dados tem mais eventos que não eventos sensitividade pode ser usado melhor que especificidade. Com aumento de precisão há uma verissimilhança maior que modelos podem ser diferenciados em termos de sensitividade do que especificidade.
#message = FALSE, warning = FALSE
library(AppliedPredictiveModeling)
library("caret")
Loading required package: lattice
Loading required package: ggplot2
data(twoClassData)
#samples to be predicted
str(predictors)
'data.frame': 208 obs. of 2 variables:
$ PredictorA: num 0.158 0.655 0.706 0.199 0.395 ...
$ PredictorB: num 0.1609 0.4918 0.6333 0.0881 0.4152 ...
#outcome classes are in a vector
str(classes)
Factor w/ 2 levels "Class1","Class2": 2 2 2 2 2 2 2 2 2 2 ...
#sample method creates random samples
#createPartition creates stratified samples of data
#Set the seed
set.seed(1)
#return a matrix of numbers
list = FALSE
trainingRows <- createDataPartition(classes,
p = 0.8,
list = list)
head(trainingRows)
Resample1
[1,] 1
[2,] 2
[3,] 3
[4,] 4
[5,] 5
[6,] 6
#subseting objects into training set
trainPredictors <- predictors[trainingRows, ]
trainClasses <- classes[trainingRows]
testPredictors <- predictors[-trainingRows, ]
testClasses <- classes[-trainingRows]
str(trainPredictors)
'data.frame': 167 obs. of 2 variables:
$ PredictorA: num 0.158 0.655 0.706 0.199 0.395 ...
$ PredictorB: num 0.1609 0.4918 0.6333 0.0881 0.4152 ...
str(testPredictors)
'data.frame': 41 obs. of 2 variables:
$ PredictorA: num 0.0658 0.1056 0.2909 0.4129 0.0472 ...
$ PredictorB: num 0.1786 0.0801 0.3021 0.2869 0.0414 ...
#to generate a test set with maximum dissimilarity: maxdissim
#Ressampling: repeated training/teste
repeatedSplits <- createDataPartition(trainClasses,
p = 0.80,
#generate multiple splits
time = 3)
str(repeatedSplits)
List of 3
$ Resample1: int [1:135] 1 2 3 4 5 6 7 8 9 10 ...
$ Resample2: int [1:135] 1 2 3 5 8 9 10 11 12 14 ...
$ Resample3: int [1:135] 1 2 3 4 5 6 7 9 13 14 ...
# bootstraping: createRessamples
# k-fold crossvalidation: createFolds
# repeated cross validation: createMultiFolds
#
set.seed(2019)
cvSplits <- createFolds(trainClasses,
k=10,
returnTrain = TRUE)
str(cvSplits)
List of 10
$ Fold01: int [1:151] 1 2 3 4 5 6 7 8 9 10 ...
$ Fold02: int [1:151] 1 2 3 4 5 6 7 8 9 10 ...
$ Fold03: int [1:150] 1 2 3 4 6 7 8 9 10 11 ...
$ Fold04: int [1:150] 1 2 3 5 7 8 9 10 11 12 ...
$ Fold05: int [1:150] 1 4 5 6 7 8 9 10 13 14 ...
$ Fold06: int [1:150] 1 2 3 4 5 6 8 9 10 11 ...
$ Fold07: int [1:151] 1 2 3 4 5 6 7 8 9 11 ...
$ Fold08: int [1:150] 2 3 4 5 6 7 8 9 10 11 ...
$ Fold09: int [1:150] 1 2 3 4 5 6 7 10 11 12 ...
$ Fold10: int [1:150] 1 2 3 4 5 6 7 8 9 10 ...
#get the first set of row numbers from the list
fold <- cvSplits[[1]]
print(fold)
[1] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 16 17 18 20 21 22 23 24 25 26 27 29 30 31 33 34 35 36 38 39
[35] 40 41 42 43 44 45 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 64 65 66 67 68 69 70 71 72 73 74 75
[69] 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
[103] 111 112 113 115 116 117 119 120 121 122 123 124 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 145 147 149 150
[137] 151 152 153 154 155 156 157 158 159 160 161 163 164 165 166
#To get 90% of the data(the first fold)
cvPredictors1 <- trainPredictors[fold,]
csClasses1 <- trainClasses[fold]
nrow(trainPredictors)
[1] 167
nrow(cvPredictors1)
[1] 151
Agora temos o conjunto de treino e teste podemos fitar um modelo de knn com 5 vizinhos. Há vários pacotes em R para essa tarfea, MASS, ipred e caret, usaremos o knn3 do pacote caret que produz a probabilidade de classes e a proporção de vizinhos associado a cada classe. Em R podemos usar duas formas para descrever modelos, a notação fórmula e a matricial. Na notação fórmula o lado esquerdo é a saída do modelo e o lado direito é como os preditores se relacionam para criar a saída, exemplo: modelFunction(price ~ numBedrooms + numBaths + acres, data = housingData) nesse caso como 3 features quantitativas se relacionam para resolver o problema.
A fórmula y~. indica uso de todos as colunas da matriz (com excessão de y) para predizer o output, essa notação é prática permitindo calcular funções dentro da fórmula, como tirar o logaritmo, mas consome muita memória. A interface matricial exige a matriz de dados dentro da função de modelagem, exemplo: modelFunction(x = housingData, y = price). Nem todas as funções em R possuem ambas as interfaces.
Podemos treinar o knn3 da seguinte forma:
trainPredictor <- as.matrix(trainPredictors)
knnFit <- knn3(x = trainPredictor, y = trainClasses, k = 5)
knnFit
5-nearest neighbor model
Training set outcome distribution:
Class1 Class2
89 78
O objeto knnFit está pronto para predizer novos valores, para tal usamos a função predict
testePredictions <- predict(knnFit, newdata = testPredictors, type= "class")
head(testePredictions)
[1] Class2 Class2 Class1 Class1 Class2 Class2
Levels: Class1 Class2
str(testePredictions)
Factor w/ 2 levels "Class1","Class2": 2 2 1 1 2 2 2 2 2 2 ...
O valor de type varia de acordo com a função de modelagem.
Para escolher os parâmetros de tunning usando reamostragem, diversos conjuntos são avaliados usando amostras distintas de dados. Pode-se criar um profile para avaliar o impacto dos parâmetros sobre o desempenho, focaremos aqui no uso do método: train do pacote caret que tem suporte a 144 modelos e diversas técnicas de reamostragem.
O SVm treinado anteriormente usou um kernel RBF que possuí o parâmetro \(\sigma\) o qual pode ser estimado analiticamente de acordo com algumas pesquisas científicas. O pacote caret faz essa estimativa automaticamente deixando a cargo do analista somente a função custo, a seguir vamos treinar um modelo usando dados de crédito de um banco Alemão.
library(caret)
data(GermanCredit)
## First, remove near-zero variance predictors then get rid of a few predictors
## that duplicate values. For example, there are two possible values for the
## housing variable: "Rent", "Own" and "ForFree". So that we don't have linear
## dependencies, we get rid of one of the levels (e.g. "ForFree")
GermanCredit <- GermanCredit[, -nearZeroVar(GermanCredit)]
GermanCredit$CheckingAccountStatus.lt.0 <- NULL
GermanCredit$SavingsAccountBonds.lt.100 <- NULL
GermanCredit$EmploymentDuration.lt.1 <- NULL
GermanCredit$EmploymentDuration.Unemployed <- NULL
GermanCredit$Personal.Male.Married.Widowed <- NULL
GermanCredit$Property.Unknown <- NULL
GermanCredit$Housing.ForFree <- NULL
## Split the data into training (80%) and test sets (20%)
set.seed(100)
inTrain <- createDataPartition(GermanCredit$Class, p = .8)[[1]]
GermanCreditTrain <- GermanCredit[ inTrain, ]
GermanCreditTest <- GermanCredit[-inTrain, ]
set.seed(1056)
svmFit <- train(Class~.,
data=GermanCreditTrain,
#tipo de kernel usado
method = "svmRadial",
#centralizar e escalar os valores
preProc = c("center", "scale"),
#usar valores específicos de kernel
tuneLength = 10,
#How to ressample the model during the training
trControl = trainControl(method = "repeatedcv",
repeats = 5,
classProbs = TRUE)
)
Podemos plotar o resultado do profile para facilitar a escolha de melhor modelo:
plot(svmFit, scale= list(x = list(log = 2)))
Para predizer novos valores com essa classe usamos:
predictedClasses <- predict(svmFit, GermanCreditTest)
str(predictedClasses)
Factor w/ 2 levels "Bad","Good": 1 1 2 2 1 2 2 2 1 1 ...
predictedProbs <- predict(svmFit, GermanCreditTest, type = "prob")
str(predictedProbs)
'data.frame': 200 obs. of 2 variables:
$ Bad : num 0.571 0.503 0.338 0.103 0.623 ...
$ Good: num 0.429 0.497 0.662 0.897 0.377 ...
head(predictedProbs)
NA
NA
Vamos comparar uma logistica com o SVM, primeiro vamos treinar a logistica
set.seed(1056)
logisticaFit <- train(Class~.,
data=GermanCreditTrain,
#tipo de kernel usado
method = "glm",
#How to ressample the model during the training
trControl = trainControl(method = "repeatedcv",
repeats = 5)
)
logisticaFit
Generalized Linear Model
800 samples
41 predictor
2 classes: 'Bad', 'Good'
No pre-processing
Resampling: Cross-Validated (10 fold, repeated 5 times)
Summary of sample sizes: 720, 720, 720, 720, 720, 720, ...
Resampling results:
Accuracy Kappa
0.748 0.3573223
Paara comparar esses dois modelos, dado que ambos foram fitados sobre os mesmos dados reamostrados, podemos usar o método ressample.
ressamp <- resamples(list(SVM = svmFit, Logistic = logisticaFit))
summary(ressamp)
Call:
summary.resamples(object = ressamp)
Models: SVM, Logistic
Number of resamples: 50
Accuracy
Min. 1st Qu. Median Mean 3rd Qu. Max. NA's
SVM 0.6875 0.725000 0.75625 0.75325 0.7750 0.8250 0
Logistic 0.6250 0.715625 0.75000 0.74800 0.7875 0.8375 0
Kappa
Min. 1st Qu. Median Mean 3rd Qu. Max. NA's
SVM 0.11971831 0.2774423 0.3436717 0.3320549 0.3729167 0.5270270 0
Logistic -0.01351351 0.2797677 0.3670683 0.3573223 0.4471501 0.5886076 0
Observamos que as distribuições estão parecidas, a coluna NA é para valores com erros de cálculo numérico. A diferença entre os métodos pode ser visualizada com
modelDifferences <- diff(ressamp)
summary(modelDifferences)
Call:
summary.diff.resamples(object = modelDifferences)
p-value adjustment: bonferroni
Upper diagonal: estimates of the difference
Lower diagonal: p-value for H0: difference = 0
Accuracy
SVM Logistic
SVM 0.00525
Logistic 0.3474
Kappa
SVM Logistic
SVM -0.02527
Logistic 0.08531
O p-valor para a comparação dos modelos é grande \(0.592\) para acurácia e \(0.269\) para Kappa, mostrando que o modelo falha em mostrar qualquer diferença de performance entre modelos. Obs: coeficiente de concordância Kappa é uma
Para escolher métodos de split de dados devemos considerar dois fatores:
Para esse dataset temos \(12495\) o número de preditores é de \(191\) como o número de instâncias é mais que \(65\) vezes maior que o número de preditores podemos dividir o conjunto em: i) treino e ii) teste. Esse split nos permite avaliar o desempenho do modelo sem impactar na tunagem dos parâmetros, antes de tomar esse decisão vamos analisar a dsitribuição das classes em relação as instâncias
A figura acima mostra o desbalanceamento entre classes, Metal (\(7\%\)) e Classica (\(28\%\)) sendo os extremos do desbalanceamento. Mesmo com esse desbalanceamento temos muitos dados tal que técnicas como validação cruzada e reamostragem tem possiblidade alta de selecionar exemplos de cada classe.
Em seguida devemos considerar o custo computacional de cada técnica uma validação cruzada para k pequeno (\(5-10\)) não será tão custoso. Entretanto repeated training/teste e bootstrap produzem resultados mais precisos na tunagem do modelo e validação.
A função createDataPartition pode ser usada para criar os folds e manter a distribuição desbalanceada entre classes.
set.seed(31)
tenFoldCv <- createFolds(trainClasses, k = 10, list = FALSE, returnTrain = TRUE)
tenFoldCv
[1] 7 4 8 1 3 10 4 3 7 3 6 1 6 1 6 2 6 7 9 9 2 2 8 7 4 4 1 4 5 4 9 10 10 3 5 6 5 7 2 8 3 5 8 8 10 9
[47] 2 3 6 1 1 1 10 9 9 2 6 8 10 3 5 7 5 3 4 9 5 7 6 4 1 5 9 8 10 7 2 8 2 9 3 7 2 9 10 9 9 9 9 2 4 8
[93] 6 3 4 1 8 8 5 3 5 2 7 2 10 6 4 2 5 3 4 4 8 10 7 1 1 3 6 6 10 6 10 3 5 8 2 10 9 8 7 1 4 3 6 3 6 6
[139] 5 8 8 10 1 5 2 5 3 8 7 9 7 4 2 1 7 1 1 10 6 10 7 7 9 1 4 5 4